package com.hq.ims.data.aop;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.hq.authority.utils.AppUtils;
import com.hq.ims.data.annotation.UserOperationMonitor;
import com.hq.ims.data.event.AddLogUserOperationEvent;
import com.hq.ims.data.vo.LogUserOperationBean;
import com.hq.utils.util.BaseConstant;
import com.hq.utils.util.StringUtils;
import com.hq.utils.vo.ReturnVo;
import com.hq.web.utils.WebUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.reflect.Method;
import java.util.Arrays;

/**
 * 用户操作aop
 */
@Aspect
@Component
@Slf4j
public class UserOperationLogAop {

    @Resource
    private ApplicationContext applicationContext;

    public UserOperationLogAop() {
    }

    @AfterReturning(value = "@annotation(com.hq.ims.data.annotation.UserOperationMonitor)", returning = "result")
    public void userOperationRecord(JoinPoint joinPoint, ReturnVo result) throws NoSuchMethodException, IOException {
        LogUserOperationBean logUserOperationBean = new LogUserOperationBean();
        String uri = WebUtils.getUrl();
        //获取目标类
        Class clazz = joinPoint.getTarget().getClass();
        //获取目标方法名称
        String methodName = joinPoint.getSignature().getName();
        //获取目标方法参数
        Class<?>[] parameterTypes = ((MethodSignature) joinPoint.getSignature()).getMethod().getParameterTypes();
        //获取req
        HttpServletRequest req = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getRequest();
        //req输入流获取到前端输入参数
        BufferedReader stream = new BufferedReader(new InputStreamReader(req.getInputStream(), BaseConstant.UTF8_STR));
        StringBuilder sb = new StringBuilder();
        //临时搬运变量
        String tempStr = null;
        //标识str是否包含Array
        while ((tempStr = stream.readLine()) != null) {
            sb.append(tempStr);
        }
        String parameter = new String();
        if (StringUtils.isNotEmpty(sb.toString()) && sb.charAt(0) == '[') {
            JSONArray objects = JSONObject.parseArray(sb.toString());
            parameter = objects.toString();
        } else if (StringUtils.isNotEmpty(sb.toString())) {
            parameter = sb.toString();
        }
        //通过方法名称以及参数名称获取方法
        Method method = clazz.getMethod(methodName, parameterTypes);
        //获取用户操作记录
        UserOperationMonitor userOperationMonitor = method.getAnnotation(UserOperationMonitor.class);
        //获取swagger方法说明
        ApiOperation apiOperation = method.getAnnotation(ApiOperation.class);
        //获取类swagger的api方法说明
        Api api = (Api) clazz.getAnnotation(Api.class);
        //完成用户操作详情
        String operating = "未知";
        if (userOperationMonitor != null) {
            StringBuilder sbOperation = new StringBuilder();
            if (api != null) {
                sbOperation.append("模块: ");
                sbOperation.append(Arrays.toString(api.tags()));
                sbOperation.append(" , 业务: [");
            }
            if (StringUtils.isNotEmpty(userOperationMonitor.value())) {
                sbOperation.append(userOperationMonitor.value());
            } else if (apiOperation != null) {
                sbOperation.append(apiOperation.value());
            }
            if (api != null) {
                sbOperation.append("]");
            }
            operating = sbOperation.toString();
        }
        //设置用户操作的结果
        logUserOperationBean.setOperate(operating);
        logUserOperationBean.setResult(result.getIsSuccess());
        logUserOperationBean.setMsg(result.getMsg());
        logUserOperationBean.setUrl(uri);
        logUserOperationBean.setLoginEquipment(WebUtils.getDevice());
        logUserOperationBean.setCompanyId(WebUtils.getRequestHead("companyId"));
        logUserOperationBean.setOperationIp(StringUtils.ifEmptyDefault(WebUtils.getIp(), "未知ip"));
        logUserOperationBean.setParam(parameter);
        String userId = AppUtils.getUserId();
        logUserOperationBean.setUserId(StringUtils.ifEmptyDefault(userId, "未知用户"));
        this.applicationContext.publishEvent(new AddLogUserOperationEvent(this, logUserOperationBean));
    }
}
